package cn.iotab.iotkit.transport.api.access.handler.impl;

import cn.iotab.iotkit.transport.api.access.device.AbstractDeviceMessageHandler;
import cn.iotab.iotkit.transport.api.access.device.listener.DeviceEventHandler;
import cn.iotab.iotkit.transport.api.access.device.listener.firmware.DeviceReportFirmwareListener;
import cn.iotab.iotkit.transport.api.access.device.listener.firmware.DeviceReportUpgradeProgressListener;
import cn.iotab.iotkit.transport.api.access.device.listener.firmware.DeviceRequestFirmwareListener;
import cn.iotab.iotkit.transport.api.access.model.custom.ProtocolConstant;
import cn.iotab.iotkit.transport.api.access.model.message.CommonDeviceMessageReply;
import cn.iotab.iotkit.transport.api.access.model.message.DeviceMessage;
import cn.iotab.iotkit.transport.api.access.model.message.DeviceMessageReply;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class DefaultProductMessageHandler extends AbstractDeviceMessageHandler<DeviceMessage> {

    private final String productKey;
    /**
     * key: originType
     */
    private final Map<String, AbstractDeviceMessageHandler<?>> handlers = new ConcurrentHashMap<>();

    public DefaultProductMessageHandler(String productKey) {
        this.productKey = productKey;
    }

    public void registerCustomHandler(String key, AbstractDeviceMessageHandler<?> handler) {
        handlers.put(key, handler);
    }

    public void registerEventHandler(String eventId, DeviceEventHandler handler) {
        handlers.put(ProtocolConstant.EVENT_PREFIX + eventId, handler);
    }

    public void registerFirmwareRequestHandler(DeviceRequestFirmwareListener handler) {
        handlers.put(ProtocolConstant.FIRMWARE_REQUEST, handler);
    }

    public void registerFirmwareReportHandler(DeviceReportFirmwareListener handler) {
        handlers.put(ProtocolConstant.FIRMWARE_REPORT, handler);
    }

    public void registerUpgradeProgressHandler(DeviceReportUpgradeProgressListener handler) {
        handlers.put(ProtocolConstant.FIRMWARE_PROGRESS, handler);
    }

    @Override
    protected ListenableFuture<DeviceMessageReply> doProcess(DeviceMessage message) {
        if (!StringUtils.equals(productKey, PRODUCT_KEY_DEFAULT) && !StringUtils.equals(productKey, message.getProductKey())) {
            throw new IllegalStateException("productKey not match, expect: " + productKey + ", message: " + message.getProductKey());
        }
        //dispatch
        AbstractDeviceMessageHandler<?> handler = handlers.get(message.getOriginType());
        if (handler == null) {
            log.error("product[" + productKey + "] has no handler for message: " + message.getOriginType() + ", ignore message");
            DeviceMessageReply reply = CommonDeviceMessageReply.commonErrorReply(message, ProtocolConstant.CODE_NOT_FOUND, "no handler for this message");
            return Futures.immediateFuture(reply);
        }
        //
        return handler.process(message);
    }
}
